define(['../../com/base', 'jquery', 'underscore'], function(Base, $, _){
  var HORIZONTAL = 1;
  var VERTICAL   = 2;
  var cssTpl     = ['.<%=spriteClass%>{',
                    ' background:url(sprite.png) no-repeat scroll center center;',
                    ' background-size:<%=totalWidth%>px <%=totalHeight%>px;',
                    '}',
                    '<%_.each(sprite,function(item, index){%>',
                      '.<%=spriteClass%>.<%=classPrefix%><%=item.name%><%=classSuffix%>{',
                      ' background-position:<%if(item.offsetX!==0){%>-<%=item.offsetX%>px<%}else{%>0<%}%> <%if(item.offsetY!==0){%>-<%=item.offsetY%>px<%}else{%>0<%}%>;',
                      ' width:<%=item.width%>px;',
                      ' height:<%=item.height%>px;',
                      '}',
                    '<%});%>'].join('\n');

  var DisplayCanvas = Base.extend({
    initializer: function(){
      this.bind();
    },
    bind: function(){
      var self = this;

      self.on('add:to:canvas', function(data){
        var files = self.get('files');
        files.push(data.data);
        self.computeImagePositions();
        self.redraw();
        self.updateStyleSheet();
      });

      self.on('afterChange:interval afterChange:direction afterChange:background', function(){
        self.computeImagePositions();
        self.redraw();
        self.updateStyleSheet();
      });
      self.on('afterChange:spriteClass afterChange:classPrefix afterChange:classSuffix', function(e){
        self.updateStyleSheet();
      });

      self.bindMoveImage();
    },
    bindMoveImage: function(){
      var self = this;
      var canvas = self.get('el');
      self.activeIdx = -1;
      var activeFile;
      var startX     = -1;
      var startY     = -1;
      var originalX, originalY;

      var mapToLogical = function(x, y){
        var phisicalWidth = canvas.width();
        var logicalWidth  = canvas[0].width;
        return {
          x : x * logicalWidth / phisicalWidth,
          y : y * logicalWidth / phisicalWidth
        };
      };

      canvas.on('mousedown', function(e){
        var files = self.get('files');
        var point = mapToLogical(e.offsetX, e.offsetY);
        startX = point.x;
        startY = point.y;

        self.activeIdx = self.computeMousePosition(startX, startY);
        if(self.activeIdx !== -1){
          activeFile = files[self.activeIdx];
          originalX = activeFile.offsetX;
          originalY = activeFile.offsetY;
        }
      });
      canvas.on('mousemove', function(e){
        if(self.activeIdx !== -1){
          var point = mapToLogical(e.offsetX, e.offsetY);
          activeFile.offsetX = originalX + point.x - startX;
          activeFile.offsetY = originalY + point.y - startY;
          self.redraw();
        }
      });
      canvas.on('mouseup', function(e){
        var files = self.get('files');
        if(self.activeIdx !== -1){
          var point = mapToLogical(e.offsetX, e.offsetY);
          var insertIndex = self.computeMouseBefore(point.x, point.y);
          var newFileSet;
          var activeIdx = self.activeIdx;

          if(insertIndex === -1){
            newFileSet = files.slice(0, activeIdx).concat(files.slice(activeIdx+1)).concat(activeFile);
          }else{
            if(activeIdx < insertIndex){
              newFileSet = files.slice(0, activeIdx).concat(files.slice(activeIdx+1,insertIndex)).concat(activeFile).concat(files.slice(insertIndex));
            }else{
              newFileSet = files.slice(0, insertIndex).concat(activeFile).concat(files.slice(insertIndex,activeIdx)).concat(files.slice(activeIdx+1));
            }
          }
          self.set('files', newFileSet);

          self.computeImagePositions();
          self.redraw();
          self.updateStyleSheet();

          self.activeIdx = -1;
        }
      });
      canvas.on('mouseleave', function(){
        if(self.activeIdx !== -1){
          var files = self.get('files');
          var newFileSet = {};

          newFileSet = files.slice(0, self.activeIdx).concat(files.slice(self.activeIdx+1));
          self.set('files', newFileSet);

          self.activeIdx = -1;
          self.computeImagePositions();
          self.redraw();
          self.updateStyleSheet();
        }
      });
    },

    computeImagePositions : function(){
      var self = this;
      var files = self.get('files');
      var summeryWidth= 0;
      var direction = self.get('direction');
      var width = direction === HORIZONTAL ? 'width' : 'height';
      var height = direction === HORIZONTAL ? 'height' : 'width';
      var offsetX = direction === HORIZONTAL ? 'offsetX' : 'offsetY';
      var offsetY = direction === HORIZONTAL ? 'offsetY' : 'offsetX';
      var interval = self.get('interval');
      var i;
      var maxHeight = 0;

      for(i = 0; i < files.length; ++i){
        files[i][offsetX]   = summeryWidth;
        files[i][offsetY]   = 0;
        summeryWidth += files[i][width] + interval;
        maxHeight = Math.max(maxHeight, files[i][height]);
      }
      if(direction === HORIZONTAL){
        self.set('totalWidth', summeryWidth);
        self.set('totalHeight', maxHeight);
      }else{
        self.set('totalWidth', maxHeight);
        self.set('totalHeight', summeryWidth);
      }
    },

    computeMouseBefore: function(x, y){
      var self  = this;
      var files = self.get('files');
      var direction = self.get('direction');

      for(var i = 0; i < files.length; ++i){
        var file = files[i];
        if((x <= file.offsetX && direction === HORIZONTAL) 
          || (y <= file.offsetY && direction === VERTICAL)){
           return i;
         }
      }
      return -1;
    },
    computeMousePosition: function(x, y){
      var self  = this;
      var files = self.get('files');

      for(var i = 0; i < files.length; ++i){
        var file = files[i];
        if(x >= file.offsetX 
           && x <= file.offsetX + file.width
           && y >= file.offsetY
           && y <= file.offsetY + file.height){
             return i;
        }
      }
      return -1;
    },
    redraw: function(files){
      var self        = this;
      var files       = self.get('files');
      var totalWidth  = self.get('totalWidth');
      var totalHeight = self.get('totalHeight');
      var bgc         = self.get('background');
      var el          = self.get('el');
      var ctx         = el[0].getContext('2d');

      el[0].width  = totalWidth;
      el[0].height = totalHeight;


      ctx.clearRect(0, 0, totalWidth, totalHeight);

      if(bgc){
        ctx.fillStyle = bgc;
        ctx.fillRect(0, 0, totalWidth,totalHeight);
      }

      for(i = 0; i < files.length; ++i){
        var image = new Image();
        image.src = files[i].data;
        ctx.drawImage(image, files[i].offsetX, files[i].offsetY);
      }
      if(self.activeIdx !== undefined && self.activeIdx !== -1){
        var image = new Image();
        image.src = files[self.activeIdx].data;
        ctx.drawImage(image, files[self.activeIdx].offsetX, files[self.activeIdx].offsetY);
      }
    },
    /**
     * 根据每个sprite的起点，计算新的css
     * @method updateStyleSheet
     * @private
     * */
    updateStyleSheet: function(){
      var self      = this;
      var data = {
        spriteClass : self.get('spriteClass'),
        totalWidth  : self.get('totalWidth'),
        totalHeight : self.get('totalHeight'),
        classPrefix : self.get('classPrefix'),
        classSuffix : self.get('classSuffix'),
        sprite      : self.get('files')
      };

      var newCSS = _.template(cssTpl)(data);
      self.set('css', newCSS);
    },
    getDownloadFile: function(fileType){
      return this.get('el')[0].toDataURL('image/'+fileType);
    }
  },{
    totalWidth: {
      value:0
    },
    totalHeight: {
      value:0
    },
    css: {
    },
    files: {
      value: []
    },
    //sprite类名
    spriteClass : {
      value: 'sprite'
    },
    classPrefix: {
      value: ''
    },
    classSuffix: {
      value: ''
    },
    //渲染到的canvas
    el: {
      value: '',
      set: function(v){ return $(v); }
    },
    // 图片间距
    interval: {
      value: 10,
      set: function(v){
        var newV = parseInt(v);
        if(newV === newV){
          return newV;
        }else{
          return this.get('interval');
        }
      }
    },

    direction: {
      value: HORIZONTAL,
      set: function(v){
        if(v.toLowerCase() === 'horizontal'){
          return HORIZONTAL;
        }else{
          return VERTICAL
        }
      }
    },
    background: {
      value:'',
      set: function(value){
        return value;
      }
    }
  });

  return DisplayCanvas;
});
